<?php

namespace App\Util;

use App\Models\Area;
use App\Models\ClinicCategory;
use App\Models\Doctor;
use Gregwar\Captcha\CaptchaBuilder;
use Illuminate\Support\Facades\Redis;
use Illuminate\Support\Str;
use App\User;
use Illuminate\Support\Facades\DB;
use PhpParser\Node\Stmt\DeclareDeclare;

class Tool
{
    /**
     * 获取真实IP地址
     * @return array|false|mixed|string
     */
    public static function getRealIp()
    {
        $ip = false;
        if (getenv("HTTP_CLIENT_IP") && strcasecmp(getenv("HTTP_CLIENT_IP"), "unknown")) {
            $ip = getenv("HTTP_CLIENT_IP");
        } else if (getenv("HTTP_X_FORWARDED_FOR") && strcasecmp(getenv("HTTP_X_FORWARDED_FOR"), "unknown")) {
            $ips = explode(", ", getenv("HTTP_X_FORWARDED_FOR"));
            if ($ip) {
                array_unshift($ips, $ip);
                $ip = false;
            }
            $ipscount = count($ips);
            for ($i = 0; $i < $ipscount; $i++) {
                if (!preg_match("/^(10|172\.16|192\.168)\./i", $ips[$i])) {
                    $ip = $ips[$i];
                    break;
                }
            }
        } else if (getenv("REMOTE_ADDR") && strcasecmp(getenv("REMOTE_ADDR"), "unknown")) {
            $ip = getenv("REMOTE_ADDR");
        } else if (isset($_SERVER['REMOTE_ADDR']) && $_SERVER['REMOTE_ADDR'] && strcasecmp($_SERVER['REMOTE_ADDR'], "unknown")) {
            $ip = $_SERVER['REMOTE_ADDR'];
        } else {
            $ip = "unknown";
        }
        return Tool::isIp($ip) ? $ip : "unknown";
    }

    /**
     * 检查是否是合法的IP
     * @param $ip
     * @return bool
     */
    public static function isIp($ip)
    {
        if (preg_match('/^((\d|[1-9]\d|2[0-4]\d|25[0-5]|1\d\d)(?:\.(\d|[1-9]\d|2[0-4]\d|25[0-5]|1\d\d)){3})$/', $ip)) {
            return true;
        } else {
            return false;
        }
    }

    /**
     * 验证手机号
     * @param $mobile
     * @return false|int
     */
    public static function checkMobile($mobile)
    {
        return preg_match('/^((13[0-9])|(14[5,7])|(15[0-3,5-9])|(16[0-9])|(17[0,3,5-8])|(18[0-9])|166|198|199|(147))\d{8}$/i', $mobile);
    }

    /**
     * 通过手机号生成api_token
     * @param int $phone
     * @return string
     */
    public static function RandomToken(string $phone)
    {
        if (empty($phone)) {
            return '';
        }
        return hash('sha256', Str::random(48) . md5($phone));
    }

    /**
     * 设置更新登录api_token
     * @param $api_token
     * @param $phone
     * @return false|mixed|string
     */
    public static function SetAndUpToken($api_token, $phone = null)
    {
        $expiredTime = env('REDIS_EXPIRED_LOGIN_TIME');
        if (!empty($phone)) {
            $user = User::where([['phone', $phone]])->first();
            if(!empty($user->image)){
                $user->image = Url::getHttpHost().'upload/'. $user->image;
            }
            Redis::setex($api_token, $expiredTime, json_encode($user, JSON_UNESCAPED_UNICODE));
        } else {
            //手机是空的更新操作
            $value = Redis::get($api_token);
            Redis::setex($api_token, $expiredTime, $value);
        }
    }

    /***
     * 获取客户端登录用户信息
     * @param $api_token
     * @return void
     */
    public static function getUser($api_token)
    {
//        $value = Redis::get($api_token);
//        if (!empty($value)) {
//            return \GuzzleHttp\json_decode($value, true);
//        }
        $user = User::where([['api_token', $api_token]])->first();
        if (!empty($user)) {
            if(!empty($user->image)){
                $user->image = Url::getHttpHost() .'upload/'. $user->image;
            }
            $info = $user->toArray();
            Redis::setex($api_token,env('REDIS_EXPIRED_LOGIN_TIME'),json_encode($info));
            return $info;
        }
        return [];
    }

    /**
     * 设置更新登录api_token
     * @param $api_token
     * @param $phone
     * @return false|mixed|string
     */
    public static function SetDoctorAndUpToken($api_token, $phone = null)
    {
        $expiredTime = env('REDIS_EXPIRED_LOGIN_TIME');
        if (!empty($phone)) {
            $user = Doctor::where([['account', $phone]])->first();//获取 用户记录
            $user->clinic ?? "";      //获取 科室分类
            $user->professional ?? "";//获取 所属职称
            $user->works ?? "";       //获取 所属工作室
            if ($user->is_admin != 1) {
                $user->works->store_manager = Doctor::where([['work_id', '=', $user->work_id]])->value("real_name");//获取 用户记录
            } else {
                $user->works->store_manager = $user->real_name;
            }
            $user->hidden_phone = substr_replace($user->account, '****', 3, 4);
            self::DoctorPicDeal($user);
           return  Redis::setex($api_token, $expiredTime, \GuzzleHttp\json_encode($user, JSON_UNESCAPED_UNICODE));
        } else {
            //手机是空的更新操作
            $value = Redis::get($api_token);
            Redis::setex($api_token, $expiredTime, $value);
        }
    }

    /**
     * @param $obj
     * @return mixed
     * 工作室信息图片增加全路径
     */
    public static function DoctorPicDeal(&$obj)
    {
        //科室图片处理
        if (!empty($obj->clinic)) {
            $obj->clinic->HosTclassify_picture = self::AddHost($obj->clinic->classify_picture);
        }
        //工作室处理
        if (!empty($obj->works)) {
            $obj->works->HosTlogo = self::AddHost($obj->works->logo);
            $obj->works->HosTimages = self::AddHost($obj->works->images);
            if (is_array($obj->works->work_detail) && !empty($obj->works->work_detail)) {
                $obj->works->HosTwork_detail = self::ArrayAddHost($obj->works->work_detail);
            }
        }
        //医生图片字段增加全路径

        //多图片处理
        if (is_array($obj->certificate) && !empty($obj->certificate)) {
            $obj->HosTcertificate = self::ArrayAddHost($obj->certificate);
        }
        $obj->HosTprofile = self::AddHost($obj->profile);
        $obj->HosTfront_card = self::AddHost($obj->front_card);
        $obj->HosTbehind_card = self::AddHost($obj->behind_card);
        $obj->HosTlogo = self::AddHost($obj->logo);
        $obj->HosTimages = self::AddHost($obj->images);
        $obj->HosTclassify_picture = self::AddHost($obj->classify_picture);
        return $obj;
    }

    /**
     * @param $array
     * @return array
     */
    public static function ArrayAddHost($array)
    {
        if (is_array($array)) {
            $arr = [];
            foreach ($array as $val) {
                $arr[] = self::AddHost(trim($val));
            }
            return $arr;
        } else {
            return [];
        }
    }

    /**
     * @param $path
     * @return string|void
     * 增加图片全路径
     */
    public static function AddHost($path)
    {
        if (!empty($path) && is_string($path)) {
            return Url::getHttpHost() . 'upload/' . trim($path);
        }
        return "";
    }

    /***
     * 获取医护端登录用户信息
     * @param $api_token
     * @return void
     */
    public static function getDoctorUser($api_token)
    {
        $value = Redis::get($api_token);
//        if (!empty($value)) {
//            return \GuzzleHttp\json_decode($value, true);
//        }
        $user = Doctor::where([['api_token', $api_token]])->first();
        if (!empty($user)) {
            $area = new Area();
            $user->clinic;          //科室分类
            $user->professional;    //所属职称
            $user->works;           //所属工作室
            $user->works->province_name =$area::getNameByCode($user->works->province_id);
            $user->works->city_name =$area::getNameByCode($user->works->city_id);
            $user->works->district_name =$area::getNameByCode($user->works->district_id);
            $user->works->clinic_work = (new ClinicCategory())->where([['id','=',$user->works->clinic_id]])->first();
            self::DoctorPicDeal($user);
            $user->hidden_phone = substr_replace($user->account, '****', 3, 4);
            return $user->toArray();
        }
        return [];
    }

    /** 医护端通过api_token获取用户信息
     * @param $api_token
     * @return mixed
     */
    public static function ApiTokenGetDoctorUser($api_token)
    {
        return Doctor::where([['api_token', $api_token]])->first();
    }

    /**医护端检查手机号码是否存在
     * @param $phone
     * @return void
     */
    public static function IssetUser($phone)
    {
        return Doctor::where('account', $phone)->first();
    }

    /**
     * 获取登录后的api_token
     * @param $api_token
     * @return bool
     */
    public static function GetLoginToken($api_token)
    {
        if (Redis::exists($api_token)) {
            return true;
        } else {
            return false;
        }
    }

    /**
     * 短信认证设置失效时间
     * @param $phone
     * @param $code
     * @return void
     */
    public static function SetSmsvalidator($phone, $code)
    {
        //获取env的配置信息
        //设置手机验证码60秒
        $expiredTime = env('REDIS_EXPIRED_TIME');
        $REDIS_REPEAT_TIME = env('REDIS_REPEAT_TIME'); //重复发送时间
        Redis::setex('REDIS_EXPIRED_TIME' . $phone, $expiredTime, $code);
        Redis::setex('REDIS_REPEAT_TIME' . $phone, $REDIS_REPEAT_TIME, $code);
    }

    /**
     * 检查短信失效时间是否过期
     * @param $phone
     * @return string
     */
    public static function GetSmsvalidator($phone)
    {
        $key = 'REDIS_EXPIRED_TIME' . $phone;
        $value = Redis::get($key);
        if (!empty($value)) {
            return $value;
        } else {
            return '';
        }
    }

    /**
     * 短信验证码验证后删除key
     * @param $phone
     * @return string
     */
    public static function UsetSmsCode($phone)
    {
        $key = 'REDIS_EXPIRED_TIME' . $phone;
        Redis::del($key);
    }

    /**
     * 设置重复登录字段用于判断重复登录
     * @param $phone
     * @param $value
     * @return void
     */
    public static function SetLoginToken($phone, $value)
    {
        $expiredTime = env('REDIS_EXPIRED_LOGIN');
        $key = 'REDIS_EXPIRED_TEMP_LOGIN-' . $phone;
        Redis::setex($key, $expiredTime, $value);
    }

    /**
     * 医护端登录设置重复登录字段用于判断重复登录
     * @param $phone
     * @param $value
     * @return void
     */
    public static function SetDoctorLoginToken($phone, $value)
    {
        $expiredTime = env('REDIS_EXPIRED_LOGIN');
        $key = 'REDIS_EXPIRED_TEMP_DOCTOR_LOGIN-' . $phone;
        Redis::setex($key, $expiredTime, $value);
    }

    /**频繁登录获取数据
     * @param $phone
     * @return string
     */
    public static function GetTempLoginToken($phone): string
    {
        //这里key在.env文件定义的
        $key = 'REDIS_EXPIRED_TEMP_LOGIN-' . $phone;
        $value = Redis::get($key);
        if (!empty($value)) {
            return $value;
        } else {
            return '';
        }
    }

    /**
     * 获取图片验证码
     * @param $phone
     * @return array
     */
    public static function CaptchaCode($phone): array
    {
        $captchaBuilder = new CaptchaBuilder();
        $key = 'captcha-' . $phone;
        //$key = 'captcha-' . str_random(15);
        $captcha = $captchaBuilder->build();
        $expiredTime = env('REDIS_EXPIRED_TIME');//过期时间60秒
        Redis::setex($key, $expiredTime, $captcha->getPhrase());
        return [
            'captcha_key' => $key,
            'expired_at' => $expiredTime,
            'captcha_image' => $captcha->inline()
        ];
    }

    /**
     * 获取验证码
     * @return void
     */
    public static function GetCapthCode($phone)
    {
        $key = 'captcha-' . $phone;
        $value = Redis::get($key);
        if (!empty($value)) {
            return $value;
        } else {
            return '';
        }
    }


    /****
     * @return mixed
     * 获取数据库sql
     */
    public static function start()
    {
        return DB::connection()->enableQueryLog();
    }

    public static function ends()
    {
        $logs = DB::getQueryLog();
        dd($logs);
    }


    /***
     * Url加域名
     */
    public function addHostToImage($data)
    {
        if (empty($data)) {
            return [];
        }
        if (is_array($data)) {
            $img_data = [];
            foreach ($data as $kk => $vv) {
                if($vv){
                    $img_data[] = env('APP_URL') . '/upload/' . trim($vv);
                }
            }
            return $img_data;
        } else {
            $img_data = env('APP_URL') . '/upload/' . $data;
            return $img_data;
        }
    }


    /**
     * 迭代器方法，实现无限分类树
     * @param array $array 原始数据包
     * @return array
     */
    public static function buildTree($array)
    {
        if (empty($array)) {
            return [];
        }
        $map = array();
        $fotmatTree = array();
        foreach ($array as &$vo) {
            $map[$vo['id']] = &$vo;
//            $map[$vo['id']]['child'] = array();
        }
        unset($vo);
        foreach ($array as &$item) {
            $parent = &$map[$item['pid']];
            if (empty($parent)) {
                $fotmatTree[] = &$item;
            } else {
                $parent['child'][] = &$item;

            }
        }
        unset($map);
        return $fotmatTree;
    }

    /**
     * 检查是否是base64编码数据
     * @param $str
     * @return bool
     */
    public static function issetBase64($str): bool
    {
        $originalLength = strlen($str);
        // 对于标准Base64编码，长度应该是4的倍数；对于URL安全的Base64编码，长度应该是3的倍数
        return $originalLength % 4 === 0 || $originalLength % 3 === 0;
    }


    /**
     * @param $str
     * @return array处理字符串编数组
     */
    public static function handelString($str)
    {
        if (empty($str)) {
            return [];
        }
        $left = ltrim($str, "[");
        $string = rtrim($left, "]");
        $array = explode(',', $string);
        $result = [];
        foreach ($array as $k => $v) {
            if (trim($v) == null || trim($v) == 'null' || trim($v) == "" || empty(trim($v))) {
                continue;
            }
            $result[] = trim($v);
        }
        return $result;
    }

    /**
     * 时间差计算
     *
     * @param Timestamp $time 时间差
     * @return String Time Elapsed
     * @author jakehu (http://www.111cn.net/)
     */
    public static function time2Units($time)
    {
        $year = floor($time / 60 / 60 / 24 / 365);
        $time -= $year * 60 * 60 * 24 * 365;
        $month = floor($time / 60 / 60 / 24 / 30);
        $time -= $month * 60 * 60 * 24 * 30;
        $week = floor($time / 60 / 60 / 24 / 7);
        $time -= $week * 60 * 60 * 24 * 7;
        $day = floor($time / 60 / 60 / 24);
        $time -= $day * 60 * 60 * 24;
        $hour = floor($time / 60 / 60);
        $time -= $hour * 60 * 60;
        $minute = floor($time / 60);
        $time -= $minute * 60;
        $elapse = '';
        $unitArr = array('年前' => 'year', '个月前' => 'month', '周前' => 'week', '天前' => 'day',
            '小时前' => 'hour', '分钟前' => 'minute', '秒前' => 'second');
        foreach ($unitArr as $cn => $u) {
            if ($year > 0) {//大于一年显示年月日
                $elapse = date('Y/m/d', time() - $time);
                break;
            } else if ($$u > 0) {
                $elapse = $$u . $cn;
                break;
            }
        }
        return $elapse;
    }

    /**
     * @param $param
     * 取环信获用户名称和密码
     */
    public static function getUserNameForIm($param)
    {
        if ($param['type'] == 1) {
            $username = 'user' . config("omnipay.Im.salt") . $param['user_id'];
            $password = 'user' . config("omnipay.Im.salt") . $param['user_id'];
        } elseif ($param['type'] == 2) {
            $username = 'doctor' . config("omnipay.Im.salt") . $param['user_id'];
            $password = 'doctor' . config("omnipay.Im.salt") . $param['user_id'];
        } elseif ($param['type'] == 3) {//供应商账号生成规则
            $username = 'suppliers' . config("omnipay.Im.salt") . $param['user_id'];
            $password = 'suppliers' . config("omnipay.Im.salt") . $param['user_id'];
        }elseif ($param['type'] == 4) {//管理后端生成规则
            $username = 'admin' . config("omnipay.Im.salt") . $param['user_id'];
            $password = 'admin' . config("omnipay.Im.salt") . $param['user_id'];
        }
        $data['username'] = $username;
        $data['password'] = $password;
        return $data;
    }

    /**
     * @param $prefix
     * @return string
     * 生成全站唯一用户名
     */
    public static function generateUniqueUsername($prefix = 'user')
    {
        static $count = 0; //静态计数器
        $count++; //增加计数器
        $timestamp = microtime(true); //获取当前时间戳（以秒为单位）
        $microseconds = sprintf("%06d", ($timestamp - (int)$timestamp) * 1000000); //微秒部分转换为字符串，并前面补零
        return $prefix . '_' . $microseconds . '_' . $count;
    }

    /**
     * @return \string[][]
     * 物流公司code
     */
    public static function logis_code()
    {
        return [
            ["company" => "顺丰速运", "company_code" => 'shunfeng'],
            ["company" => "京东物流", "company_code" => 'jd'],
            ["company" => "圆通速递", "company_code" => 'yuantong'],
            ["company" => "申通快递", "company_code" => 'shentong'],
            ["company" => "极兔速递", "company_code" => 'jtexpress'],
            ["company" => "中通快递", "company_code" => 'zhongtong'],
            ["company" => "韵达快递", "company_code" => 'yunda'],
            ["company" => "邮政快递包裹", "company_code" => 'youzhengguonei'],
            ["company" => "EMS", "company_code" => 'ems'],
            ["company" => "德邦快递", "company_code" => 'debangkuaidi'],
            ["company" => "菜鸟速递", "company_code" => 'danniao'],
            ["company" => "德邦", "company_code" => 'debangwuliu'],
        ];
    }


    /**
     * @param int $length
     * @return string
     * 生成随机字符串
     */
    public static function generateRandomString($length = 12)
    {
        $characters = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789';
        $randomString = '';
        $charLength = strlen($characters);
        for ($i = 0; $i < $length; $i++) {
            $randomString .= $characters[mt_rand(0, $charLength - 1)];
        }
        return strtolower($randomString);
    }

    public static function getOpenid($param)
    {
        if ($param['type'] == 1) { //用户
            $hase = (new User())->where([['id', '=', $param['user_id']]])->value("open_id");
            if ($hase) {
                return $hase;
            }
            $openid = md5(self::generateRandomString(8) . $param['type'] . $param['user_id'] . config("omnipay.Im.salt"));
            (new User())->where([['id', '=', $param['user_id']]])->update(['open_id' => $openid]);
            return $openid;
        } else { //医师
            $hase = (new Doctor())->where([['id', '=', $param['user_id']]])->value("open_id");
            if ($hase) {
                return $hase;
            }
            $openid = md5(self::generateRandomString(8) . $param['type'] . $param['user_id'] . config("omnipay.Im.salt"));
            (new Doctor())->where([['id', '=', $param['user_id']]])->update(['open_id' => $openid]);
            return $openid;
        }
    }


    public function getLatLngByAddress($address)
    {
        //高德地图的api接口,根据详细地址获取经纬度
//        $key = "dce42e5a977ae771fa0c70264482f498";
        $key = config("omnipay.gaode.key");
        $address_location = "https://restapi.amap.com/v3/geocode/geo?address=" . $address . "&output=JSON&key=" . $key;
        $data_location = file_get_contents($address_location);
        $result_local = json_decode($data_location, true);
        //返回数据状态1 为成功 0 为失败
        $local_status = $result_local['status'];
        //返回状态码 10000 为正确 其他为错误
        $local_infocode = $result_local['infocode'];
        // return $result_local;
        if ($local_status == 1 && $local_infocode == 10000) {
            //地址信息的数组
            $local_geocode = $result_local['geocodes'];
            $location = $local_geocode[0]['location'];
            $location_ay = explode(",", $location);
            return [
                'longitude' => $location_ay[0],
                'latitude' => $location_ay[1],
            ];
        } else {
            return ['status' => 0, 'msg' => '地图API调用失败'];
        }
    }


    public function getAddresByLng($param)
    {
        $lat = $param['lat'];
        $lng = $param['lng'];
// 替换为自己的高德地图开发者Key
        $key = config("omnipay.gaode.key");
        $url = 'https://restapi.amap.com/v3/place/around?key=' . $key . '&location=' . $lng . ',' . $lat . '&output=json&radius=1000&keywords=';
        $response = file_get_contents($url);
// 解析JSON响应
        $result = json_decode($response, true);
        if ($result['status'] == '1') {
            // 获取返回的POI信息
            if (!empty($result['pois'])) {
                $pois = $result['pois'];
                $list['province'] = $pois[0]['pname'];
                $list['city'] = $pois[0]['cityname'];
                $list['county'] = $pois[0]['adname'];
                return $list;
            }
            return [];
        } else {
            echo '获取周边POI信息失败';
        }
    }
}